#include "coroutineUcontext.h"
#include <ucontext.h>
#include <memory>
#include <iostream>
#include "../logger/logger.h"
namespace TinyRPC{

// 线程对应的主协程的生命周期归mainCoroutine管理
// 线程结束时, mainCoroutine变量销毁, 其管理的主协程堆内存也销毁
thread_local CoroutineUcontextPtr mainCoroutineUcontex = nullptr;

// 线程对应的当前活跃协程， 但是其并不控制当前活跃协程的生命周期， 只是记录一下
thread_local CoroutineUcontextPtr currentCoroutineUcontex = nullptr;

CoroutineUcontext::CoroutineUcontext(CoroutineTask coroutineTask, int stackSize)
: m_coroutineTask(coroutineTask)
, m_stackSize(stackSize){
    m_coroutineStack = new char[m_stackSize];
    getcontext(&m_uContext);

    if(mainCoroutineUcontex == 0){
        // 获取线程的主协程
        GetMainCoroutine();
       
    }

    m_uContext.uc_link = &mainCoroutineUcontex->m_uContext;
    m_uContext.uc_stack.ss_sp = m_coroutineStack;
    m_uContext.uc_stack.ss_size = m_stackSize;

    makecontext(&m_uContext, &CoroutineUcontext::CoroutineFunc, 0);
    std::cout<<"coroutine() create"<<std::endl;

}


CoroutineUcontext::CoroutineUcontext()
: m_stackSize(0)
, m_coroutineStack(nullptr)
{
    getcontext(&m_uContext);
    std::cout<<"coroutine create"<<std::endl;
}

CoroutineUcontext::~CoroutineUcontext(){
    if(m_coroutineStack != nullptr){
        delete[] m_coroutineStack;
    }
    std::cout<<"destory Coroutine "<<std::endl;
}

void CoroutineUcontext::GetMainCoroutine(){
    if(mainCoroutineUcontex == nullptr){
        mainCoroutineUcontex = CoroutineUcontextPtr(new CoroutineUcontext);
        currentCoroutineUcontex = mainCoroutineUcontex;
    }
}
// 进入协程
void CoroutineUcontext::resume(){
    currentCoroutineUcontex = this->shared_from_this();
    swapcontext(&mainCoroutineUcontex->m_uContext, &m_uContext);
    currentCoroutineUcontex = mainCoroutineUcontex;
}
//退出线程
void CoroutineUcontext::Yield(){
    swapcontext(&currentCoroutineUcontex->m_uContext, &mainCoroutineUcontex->m_uContext);
}
void CoroutineUcontext::setName(const std::string& name){
    m_name = name;
}
std::string CoroutineUcontext::getName(){
    return m_name;
}

// 协程的执行入口， 里面执行用户的函数
void CoroutineUcontext::CoroutineFunc(){
    currentCoroutineUcontex->runTask();
    // 切换到主线程
    swapcontext(&currentCoroutineUcontex->m_uContext, &mainCoroutineUcontex->m_uContext);
}


bool CoroutineUcontext::InMain(){
return mainCoroutineUcontex == nullptr ||
        mainCoroutineUcontex == currentCoroutineUcontex;
}
bool CoroutineUcontext::InCoroutine(){
return currentCoroutineUcontex != nullptr  &&
        currentCoroutineUcontex != mainCoroutineUcontex;
}
void CoroutineUcontext::makeSureInMain(){
    if(mainCoroutineUcontex == nullptr){
        GetMainCoroutine();
    }
    if(!CoroutineUcontext::InMain()){
        LOG_ERROR<<"coroutine must call by main thread, donot support call by another coroutine";
        exit(1);
    }
}

std::shared_ptr<CoroutineUcontext> CoroutineUcontext::CurrentCoroutine(){
    return currentCoroutineUcontex;
}
}


